﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.Linq;
using EstateNuke.Data.Properties;

namespace EstateNuke.Data
{
    public partial class Project
    {
        #region Fileds & Properties

        /// <summary>
        /// </summary>
        public string DisplayName
        {
            get
            {
                return string.Format("{0}{1}", Name, IsDeleted ? " (已删除)" : "");
            }
        }

        /// <summary>
        /// </summary>
        public int AllSmallOrdersCount
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalRooms).SelectMany(room => room.InternalAgreements).SelectMany(agreement => agreement.InternalSmallOrders).Count();
            }
        }

        /// <summary>
        /// </summary>
        public int AllLargeOrdersCount
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalRooms).SelectMany(room => room.InternalAgreements).SelectMany(agreement => agreement.InternalLargeOrders).Count();
            }
        }

        /// <summary>
        /// </summary>
        public int AllContractsCount
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalRooms).SelectMany(room => room.InternalAgreements).SelectMany(agreement => agreement.InternalContracts).Count();
            }
        }

        /// <summary>
        /// </summary>
        public int AllLeaseOrdersCount
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalProperties).SelectMany(property => property.InternalLeaseAgreements).SelectMany(leaseAgreement => leaseAgreement.InternalLeaseOrders).Count();
            }
        }

        /// <summary>
        /// </summary>
        public int AllLeaseContractsCount
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalProperties).SelectMany(property => property.InternalLeaseAgreements).SelectMany(leaseAgreement => leaseAgreement.InternalLeaseContracts).Count();
            }
        }

        /// <summary>
        /// </summary>
        public IList<Building> Buildings
        {
            get
            {
                return InternalBuildings.Where(building => building.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<Employee> Employees
        {
            get
            {
                return InternalEmployees.Where(employee => employee.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<Customer> Customers
        {
            get
            {
                return InternalCustomers.Where(customer => customer.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        internal IList<ProjectAlertTypeSetting> ProjectAlertTypeSettings
        {
            get
            {
                return InternalProjectAlertTypeSettings.Where(projectAlertTypeSetting => projectAlertTypeSetting.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IDictionary<AlertType, Tuple<short?, short?, short?, short?>> AlertTypeReminderDays
        {
            get
            {
                return InternalProjectAlertTypeSettings.Where(projectAlertTypeSetting => projectAlertTypeSetting.IsDeleted == false && projectAlertTypeSetting.AlertType.IsDeleted == false).ToDictionary(projectAlertTypeSetting => projectAlertTypeSetting.AlertType, projectAlertTypeSetting => Tuple.Create(projectAlertTypeSetting.ReminderDays, projectAlertTypeSetting.RequirementLevel1ReminderDays, projectAlertTypeSetting.RequirementLevel2ReminderDays, projectAlertTypeSetting.RequirementLevel3ReminderDays));
            }
        }

        /// <summary>
        /// </summary>
        internal IList<ProjectRoomType> ProjectRoomTypes
        {
            get
            {
                return InternalProjectRoomTypes.Where(projectRoomType => projectRoomType.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<RoomType> RoomTypes
        {
            get
            {
                return InternalProjectRoomTypes.Where(projectRoomType => projectRoomType.IsDeleted == false && projectRoomType.RoomType.IsDeleted == false).Select(projectRoomType => projectRoomType.RoomType).ToList();
            }
        }

        /// <summary>
        /// </summary>
        internal IList<ProjectUser> ProjectUsers
        {
            get
            {
                return InternalProjectUsers.Where(projectUser => projectUser.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<User> Users
        {
            get
            {
                return InternalProjectUsers.Where(projectUser => projectUser.IsDeleted == false && projectUser.User.IsDeleted == false).Select(projectUser => projectUser.User).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<Plan> Plans
        {
            get
            {
                return InternalPlans.Where(plan => plan.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<Report> Reports
        {
            get
            {
                return InternalReports.Where(report => report.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IList<Alert> Alerts
        {
            get
            {
                return InternalAlerts.Where(alert => alert.IsDeleted == false).ToList();
            }
        }

        /// <summary>
        /// </summary>
        internal IEnumerable<CustomerCommunicationScheduledCallbackAlert> InternalCustomerCommunicationScheduledCallbackAlerts
        {
            get
            {
                return InternalCustomers.SelectMany(customer => customer.InternalCustomerCommunications).SelectMany(customerCommunication => customerCommunication.InternalCustomerCommunicationScheduledCallbackAlerts);
            }
        }

        /// <summary>
        /// </summary>
        public IList<CustomerCommunicationScheduledCallbackAlert> CustomerCommunicationScheduledCallbackAlerts
        {
            get
            {
                return InternalCustomers.Where(customer => customer.IsDeleted == false).SelectMany(customer => customer.InternalCustomerCommunications.Where(customerCommunication => customerCommunication.IsDeleted == false)).SelectMany(customerCommunication => customerCommunication.InternalCustomerCommunicationScheduledCallbackAlerts.Where(customerCommunicationScheduledCallbackAlert => customerCommunicationScheduledCallbackAlert.IsDeleted == false)).ToList();
            }
        }

        /// <summary>
        /// </summary>
        internal IEnumerable<SmallOrderExpiredAlert> InternalSmallOrderExpiredAlerts
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalRooms).SelectMany(room => room.InternalAgreements).SelectMany(agreement => agreement.InternalSmallOrders).SelectMany(smallOrder => smallOrder.InternalSmallOrderExpiredAlerts);
            }
        }

        /// <summary>
        /// </summary>
        public IList<SmallOrderExpiredAlert> SmallOrderExpiredAlerts
        {
            get
            {
                return InternalBuildings.Where(building => building.IsDeleted == false).SelectMany(building => building.InternalEntrances.Where(entrance => entrance.IsDeleted == false)).SelectMany(entrance => entrance.InternalRooms.Where(room => room.IsDeleted == false)).Select(room => room.ActiveAgreement).Where(agreement => agreement != null).SelectMany(agreement => agreement.InternalSmallOrders.Where(smallOrder => smallOrder.IsDeleted == false)).SelectMany(smallOrder => smallOrder.InternalSmallOrderExpiredAlerts.Where(smallOrderExpiredAlert => smallOrderExpiredAlert.IsDeleted == false)).ToList();
            }
        }

        /// <summary>
        /// </summary>
        internal IEnumerable<LargeOrderEngagedContractAlert> InternalLargeOrderEngagedContractAlerts
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalRooms).SelectMany(room => room.InternalAgreements).SelectMany(agreement => agreement.InternalLargeOrders).SelectMany(largeOrder => largeOrder.InternalLargeOrderEngagedContractAlerts);
            }
        }

        /// <summary>
        /// </summary>
        public IList<LargeOrderEngagedContractAlert> LargeOrderEngagedContractAlerts
        {
            get
            {
                return InternalBuildings.Where(building => building.IsDeleted == false).SelectMany(building => building.InternalEntrances.Where(entrance => entrance.IsDeleted == false)).SelectMany(entrance => entrance.InternalRooms.Where(room => room.IsDeleted == false)).Select(room => room.ActiveAgreement).Where(agreement => agreement != null).SelectMany(agreement => agreement.InternalLargeOrders.Where(largeOrder => largeOrder.IsDeleted == false)).SelectMany(largeOrder => largeOrder.InternalLargeOrderEngagedContractAlerts.Where(largeOrderEngagedContractAlert => largeOrderEngagedContractAlert.IsDeleted == false)).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IEnumerable<ContractReceiptScheduledAlert> InternalContractReceiptScheduledAlerts
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalRooms).SelectMany(room => room.InternalAgreements).SelectMany(agreement => agreement.InternalContracts).SelectMany(contract => contract.InternalContractReceipts).SelectMany(contractReceipt => contractReceipt.InternalContractReceiptScheduledAlerts);
            }
        }

        /// <summary>
        /// </summary>
        public IList<ContractReceiptScheduledAlert> ContractReceiptScheduledAlerts
        {
            get
            {
                return InternalBuildings.Where(building => building.IsDeleted == false).SelectMany(building => building.InternalEntrances.Where(entrance => entrance.IsDeleted == false)).SelectMany(entrance => entrance.InternalRooms.Where(room => room.IsDeleted == false)).Select(room => room.ActiveAgreement).Where(agreement => agreement != null).SelectMany(agreement => agreement.InternalContracts.Where(contract => contract.IsDeleted == false)).SelectMany(contract => contract.InternalContractReceipts.Where(contractReceipt => contractReceipt.IsDeleted == false)).SelectMany(contractReceipt => contractReceipt.InternalContractReceiptScheduledAlerts.Where(contractReceiptScheduledAlert => contractReceiptScheduledAlert.IsDeleted == false)).ToList();
            }
        }

        /// <summary>
        /// </summary>
        internal IEnumerable<LeaseOrderEngagedContractAlert> InternalLeaseOrderEngagedContractAlerts
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalProperties).SelectMany(property => property.InternalLeaseAgreements).SelectMany(leaseAgreement => leaseAgreement.InternalLeaseOrders).SelectMany(leaseOrder => leaseOrder.InternalLeaseOrderEngagedContractAlerts);
            }
        }

        /// <summary>
        /// </summary>
        public IList<LeaseOrderEngagedContractAlert> LeaseOrderEngagedContractAlerts
        {
            get
            {
                return InternalBuildings.Where(building => building.IsDeleted == false).SelectMany(building => building.InternalFloors.Where(floor => floor.IsDeleted == false)).SelectMany(floor => floor.InternalProperties.Where(property => property.IsDeleted == false)).Select(property => property.ActiveLeaseAgreement).Where(leaseAgreement => leaseAgreement != null).SelectMany(leaseAgreement => leaseAgreement.InternalLeaseOrders.Where(leaseOrder => leaseOrder.IsDeleted == false)).SelectMany(leaseOrder => leaseOrder.InternalLeaseOrderEngagedContractAlerts.Where(leaseOrderEngagedContractAlert => leaseOrderEngagedContractAlert.IsDeleted == false)).ToList();
            }
        }

        /// <summary>
        /// </summary>
        public IEnumerable<LeaseContractReceiptScheduledAlert> InternalLeaseContractReceiptScheduledAlerts
        {
            get
            {
                return InternalBuildings.SelectMany(building => building.InternalEntrances).SelectMany(entrance => entrance.InternalProperties).SelectMany(property => property.InternalLeaseAgreements).SelectMany(leaseAgreement => leaseAgreement.InternalLeaseContracts).SelectMany(leaseContract => leaseContract.InternalLeaseContractReceipts).SelectMany(leaseContractReceipt => leaseContractReceipt.InternalLeaseContractReceiptScheduledAlerts);
            }
        }

        /// <summary>
        /// </summary>
        public IList<LeaseContractReceiptScheduledAlert> LeaseContractReceiptScheduledAlerts
        {
            get
            {
                return InternalBuildings.Where(building => building.IsDeleted == false).SelectMany(building => building.InternalFloors.Where(floor => floor.IsDeleted == false)).SelectMany(floor => floor.InternalProperties.Where(property => property.IsDeleted == false)).Select(property => property.ActiveLeaseAgreement).Where(leaseAgreement => leaseAgreement != null).SelectMany(leaseAgreement => leaseAgreement.InternalLeaseContracts.Where(leaseContract => leaseContract.IsDeleted == false)).SelectMany(leaseContract => leaseContract.InternalLeaseContractReceipts.Where(leaseContractReceipt => leaseContractReceipt.IsDeleted == false)).SelectMany(leaseContractReceipt => leaseContractReceipt.InternalLeaseContractReceiptScheduledAlerts.Where(leaseContractReceiptScheduledAlert => leaseContractReceiptScheduledAlert.IsDeleted == false)).ToList();
            }
        }

        #endregion

        #region Add & Remove Building

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Building AddBuilding(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var building = new Building
                               {
                                   RowId = Guid.NewGuid(),
                                   CreatedDate = DateTime.Now,
                               };
            InternalBuildings.Add(building);
            building.IsDeleted = false;
            building.ModifiedDate = DateTime.Now;
            building.ModifiedByUser = modifiedUser;
            building.EntrancesNumber = 1;
            building.FloorsNumber = 1;
            building.UndergroundFloorsNumber = 0;
            building.BuildingTypeId = 1;
            building.BuildingStateId = 1;
            building.BusinessTypeId = 1;
            return building;
        }

        /// <summary>
        /// </summary>
        /// <param name = "name"></param>
        /// <param name = "modifiedUser"></param>
        /// <returns></returns>
        public Building AddBuilding(string name, User modifiedUser)
        {
            if (string.IsNullOrEmpty(name))
            {
                throw new ArgumentNullException("name");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalBuildings.Any(item => item.IsDeleted == false && item.Name == name))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.DuplicatedBuilding, name));
            }
            var building = InternalBuildings.FirstOrDefault(item => item.IsDeleted && item.Name == name);
            if (building == null)
            {
                building = new Building
                               {
                                   RowId = Guid.NewGuid(),
                                   CreatedDate = DateTime.Now,
                               };
                InternalBuildings.Add(building);
            }
            building.IsDeleted = false;
            building.ModifiedDate = DateTime.Now;
            building.ModifiedByUser = modifiedUser;
            building.Name = name;
            building.EntrancesNumber = 1;
            building.FloorsNumber = 1;
            building.UndergroundFloorsNumber = 0;
            building.BuildingTypeId = 1;
            building.BuildingStateId = 1;
            building.BusinessTypeId = 1;
            return building;
        }

        /// <summary>
        /// </summary>
        /// <param name = "building"></param>
        /// <param name = "modifiedUser"></param>
        public void RemoveBuilding(Building building, User modifiedUser)
        {
            if (building == null)
            {
                throw new ArgumentNullException("building");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalBuildings.Contains(building))
            {
                building.Delete(modifiedUser);
            }
        }

        #endregion

        #region Add & Remove Employee

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Employee AddEmployee(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var employee = new Employee
                               {
                                   RowId = Guid.NewGuid(),
                                   CreatedDate = DateTime.Now,
                               };
            InternalEmployees.Add(employee);
            employee.IsDeleted = false;
            employee.ModifiedDate = DateTime.Now;
            employee.ModifiedByUser = modifiedUser;
            return employee;
        }

        /// <summary>
        /// </summary>
        /// <param name = "employee"></param>
        /// <param name = "modifiedUser"></param>
        public void RemoveEmployee(Employee employee, User modifiedUser)
        {
            if (employee == null)
            {
                throw new ArgumentNullException("employee");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalEmployees.Contains(employee))
            {
                employee.Delete(modifiedUser);
            }
        }

        #endregion

        #region Add & Remove Customer

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Customer AddCustomer(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var customer = new Customer
                               {
                                   RowId = Guid.NewGuid(),
                                   CreatedDate = DateTime.Now,
                               };
            InternalCustomers.Add(customer);
            customer.IsDeleted = false;
            customer.ModifiedDate = DateTime.Now;
            customer.ModifiedByUser = modifiedUser;
            return customer;
        }

        /// <summary>
        /// </summary>
        /// <param name = "mobile"></param>
        /// <param name = "modifiedUser"></param>
        /// <returns></returns>
        public Customer AddCustomer(string mobile, User modifiedUser)
        {
            if (string.IsNullOrEmpty(mobile))
            {
                throw new ArgumentNullException("mobile");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalCustomers.Any(item => item.IsDeleted == false && item.Mobile == mobile))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentCulture, Resources.DuplicatedCustomer, mobile));
            }
            var customer = InternalCustomers.FirstOrDefault(item => item.IsDeleted && item.Mobile == mobile);
            if (customer == null)
            {
                customer = new Customer
                               {
                                   RowId = Guid.NewGuid(),
                                   CreatedDate = DateTime.Now,
                               };
                InternalCustomers.Add(customer);
            }
            customer.IsDeleted = false;
            customer.ModifiedDate = DateTime.Now;
            customer.ModifiedByUser = modifiedUser;
            customer.Mobile = mobile;
            return customer;
        }

        /// <summary>
        /// </summary>
        /// <param name = "customer"></param>
        /// <param name = "modifiedUser"></param>
        public void RemoveCustomer(Customer customer, User modifiedUser)
        {
            if (customer == null)
            {
                throw new ArgumentNullException("customer");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalCustomers.Contains(customer))
            {
                customer.Delete(modifiedUser);
            }
        }

        #endregion

        #region Transfer Customers

        /// <summary>
        /// </summary>
        /// <param name = "salesEmployee"></param>
        /// <param name = "otherSalesEmployee"></param>
        /// <param name = "modifiedUser"></param>
        public void TransferCustomers(Employee salesEmployee, Employee otherSalesEmployee, User modifiedUser)
        {
            if (salesEmployee == null)
            {
                throw new ArgumentNullException("salesEmployee");
            }
            if (otherSalesEmployee == null)
            {
                throw new ArgumentNullException("otherSalesEmployee");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var customers = salesEmployee.Customers;
            foreach (var customer in customers)
            {
                customer.SalesEmployee = otherSalesEmployee;
                customer.ModifiedDate = DateTime.Now;
                customer.ModifiedByUser = modifiedUser;
            }
        }

        /// <summary>
        /// </summary>
        /// <param name = "salesEmployee"></param>
        /// <param name = "otherSalesEmployees"></param>
        /// <param name = "modifiedUser"></param>
        public void TransferCustomers(Employee salesEmployee, IList<Employee> otherSalesEmployees, User modifiedUser)
        {
            if (salesEmployee == null)
            {
                throw new ArgumentNullException("salesEmployee");
            }
            if (otherSalesEmployees == null)
            {
                throw new ArgumentNullException("otherSalesEmployees");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var customers = salesEmployee.Customers;
            var customersQueue = new Queue<Customer>(customers);
            var customersCount = customers.Count;
            var otherSalesEmployeeCustomerCountDictionary = otherSalesEmployees.ToDictionary(employee => employee, employee => employee.CustomersCount);
            var otherCustomersCount = otherSalesEmployeeCustomerCountDictionary.Sum(otherSalesEmployeeCustomerCount => otherSalesEmployeeCustomerCount.Value);
            var otherSalesEmployeeReversedCustomerCountDictionary = otherSalesEmployeeCustomerCountDictionary.ToDictionary(otherSalesEmployeeCustomerCount => otherSalesEmployeeCustomerCount.Key, otherSalesEmployeeCustomerCount => otherCustomersCount - otherSalesEmployeeCustomerCount.Value);
            var otherReversedCustomersCount = otherSalesEmployeeReversedCustomerCountDictionary.Sum(otherSalesEmployeeReversedCustomerCount => otherSalesEmployeeReversedCustomerCount.Value);
            var otherSalesEmployeeAssigedDictionary = otherSalesEmployeeReversedCustomerCountDictionary.ToDictionary(otherSalesEmployeeReversedCustomerCount => otherSalesEmployeeReversedCustomerCount.Key, otherSalesEmployeeReversedCustomerCount => Math.Ceiling((otherSalesEmployeeReversedCustomerCount.Value / (double) otherReversedCustomersCount) * customersCount));
            foreach (var otherSalesEmployeeAssiged in otherSalesEmployeeAssigedDictionary)
            {
                var otherSalesEmployee = otherSalesEmployeeAssiged.Key;
                for (var index = 0; index < otherSalesEmployeeAssiged.Value; index++)
                {
                    if (customersQueue.Count > 0)
                    {
                        var customer = customersQueue.Dequeue();
                        customer.SalesEmployee = otherSalesEmployee;
                        customer.ModifiedDate = DateTime.Now;
                        customer.ModifiedByUser = modifiedUser;
                    }
                }
            }
        }

        #endregion

        #region Add & Remove ProjectAlertTypeSetting

        /// <summary>
        /// </summary>
        /// <returns></returns>
        internal ProjectAlertTypeSetting AddProjectAlertTypeSetting(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var projectAlertTypeSetting = new ProjectAlertTypeSetting
                                              {
                                                  RowId = Guid.NewGuid(),
                                                  CreatedDate = DateTime.Now,
                                              };
            InternalProjectAlertTypeSettings.Add(projectAlertTypeSetting);
            projectAlertTypeSetting.IsDeleted = false;
            projectAlertTypeSetting.ModifiedDate = DateTime.Now;
            projectAlertTypeSetting.ModifiedByUser = modifiedUser;
            return projectAlertTypeSetting;
        }

        /// <summary>
        /// </summary>
        /// <param name = "projectAlertTypeSetting"></param>
        /// <param name = "modifiedUser"></param>
        internal void RemoveProjectAlertTypeSetting(ProjectAlertTypeSetting projectAlertTypeSetting, User modifiedUser)
        {
            if (projectAlertTypeSetting == null)
            {
                throw new ArgumentNullException("projectAlertTypeSetting");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalProjectAlertTypeSettings.Contains(projectAlertTypeSetting))
            {
                projectAlertTypeSetting.Delete(modifiedUser);
            }
        }

        #endregion

        #region Set AlertTypeReminderDays

        /// <summary>
        /// </summary>
        /// <param name = "alertTypeReminderDays"></param>
        /// <param name = "modifiedUser"></param>
        public void SetAlertTypeReminderDays(IDictionary<AlertType, Tuple<short?, short?, short?, short?>> alertTypeReminderDays, User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (alertTypeReminderDays != null)
            {
                var projectAlertTypeSettings = InternalProjectAlertTypeSettings.ToList();
                projectAlertTypeSettings.ForEach(projectAlertTypeSetting => projectAlertTypeSetting.Delete(modifiedUser));
                foreach (var alertTypeReminderDay in alertTypeReminderDays)
                {
                    var currentProjectAlertTypeSetting = projectAlertTypeSettings.FirstOrDefault(projectAlertTypeSetting => projectAlertTypeSetting.AlertType == alertTypeReminderDay.Key);
                    if (currentProjectAlertTypeSetting != null)
                    {
                        currentProjectAlertTypeSetting.CancelDelete(modifiedUser);
                        currentProjectAlertTypeSetting.ReminderDays = alertTypeReminderDay.Value.Item1;
                        currentProjectAlertTypeSetting.RequirementLevel1ReminderDays = alertTypeReminderDay.Value.Item2;
                        currentProjectAlertTypeSetting.RequirementLevel2ReminderDays = alertTypeReminderDay.Value.Item3;
                        currentProjectAlertTypeSetting.RequirementLevel3ReminderDays = alertTypeReminderDay.Value.Item4;
                    }
                    else
                    {
                        currentProjectAlertTypeSetting = AddProjectAlertTypeSetting(modifiedUser);
                        currentProjectAlertTypeSetting.AlertType = alertTypeReminderDay.Key;
                        currentProjectAlertTypeSetting.ReminderDays = alertTypeReminderDay.Value.Item1;
                        currentProjectAlertTypeSetting.RequirementLevel1ReminderDays = alertTypeReminderDay.Value.Item2;
                        currentProjectAlertTypeSetting.RequirementLevel2ReminderDays = alertTypeReminderDay.Value.Item3;
                        currentProjectAlertTypeSetting.RequirementLevel3ReminderDays = alertTypeReminderDay.Value.Item4;
                    }
                }
            }
        }

        #endregion

        #region Add & Remove ProjectRoomType

        /// <summary>
        /// </summary>
        /// <returns></returns>
        internal ProjectRoomType AddProjectRoomType(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var projectRoomType = new ProjectRoomType
                                      {
                                          RowId = Guid.NewGuid(),
                                          CreatedDate = DateTime.Now,
                                      };
            InternalProjectRoomTypes.Add(projectRoomType);
            projectRoomType.IsDeleted = false;
            projectRoomType.ModifiedDate = DateTime.Now;
            projectRoomType.ModifiedByUser = modifiedUser;
            return projectRoomType;
        }

        /// <summary>
        /// </summary>
        /// <param name = "projectRoomType"></param>
        /// <param name = "modifiedUser"></param>
        internal void RemoveProjectRoomType(ProjectRoomType projectRoomType, User modifiedUser)
        {
            if (projectRoomType == null)
            {
                throw new ArgumentNullException("projectRoomType");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalProjectRoomTypes.Contains(projectRoomType))
            {
                projectRoomType.Delete(modifiedUser);
            }
        }

        #endregion

        #region Set RoomTypes

        /// <summary>
        /// </summary>
        /// <param name = "roomTypes"></param>
        /// <param name = "modifiedUser"></param>
        public void SetRoomTypes(IList<RoomType> roomTypes, User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (roomTypes != null)
            {
                var projectRoomTypes = InternalProjectRoomTypes.ToList();
                projectRoomTypes.ForEach(projectRoomType => projectRoomType.Delete(modifiedUser));
                foreach (var roomType in roomTypes.Distinct())
                {
                    var currentProjectRoomType = projectRoomTypes.FirstOrDefault(projectRoomType => projectRoomType.RoomType == roomType);
                    if (currentProjectRoomType != null)
                    {
                        currentProjectRoomType.CancelDelete(modifiedUser);
                    }
                    else
                    {
                        currentProjectRoomType = AddProjectRoomType(modifiedUser);
                        currentProjectRoomType.RoomType = roomType;
                    }
                }
            }
        }

        #endregion

        #region Add & Remove ProjectUser

        /// <summary>
        /// </summary>
        /// <returns></returns>
        internal ProjectUser AddProjectUser(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var projectUser = new ProjectUser
                                  {
                                      RowId = Guid.NewGuid(),
                                      CreatedDate = DateTime.Now,
                                  };
            InternalProjectUsers.Add(projectUser);
            projectUser.IsDeleted = false;
            projectUser.ModifiedDate = DateTime.Now;
            projectUser.ModifiedByUser = modifiedUser;
            return projectUser;
        }

        /// <summary>
        /// </summary>
        /// <param name = "projectUser"></param>
        /// <param name = "modifiedUser"></param>
        internal void RemoveProjectUser(ProjectUser projectUser, User modifiedUser)
        {
            if (projectUser == null)
            {
                throw new ArgumentNullException("projectUser");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalProjectUsers.Contains(projectUser))
            {
                projectUser.Delete(modifiedUser);
            }
        }

        #endregion

        #region Set Users

        /// <summary>
        /// </summary>
        /// <param name = "users"></param>
        /// <param name = "modifiedUser"></param>
        public void SetUsers(IList<User> users, User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (users != null)
            {
                var projectUsers = InternalProjectUsers.ToList();
                projectUsers.ForEach(projectUser => projectUser.Delete(modifiedUser));
                foreach (var user in users.Distinct())
                {
                    var currentProjectUser = projectUsers.FirstOrDefault(projectUser => projectUser.User == user);
                    if (currentProjectUser != null)
                    {
                        currentProjectUser.CancelDelete(modifiedUser);
                    }
                    else
                    {
                        currentProjectUser = AddProjectUser(modifiedUser);
                        currentProjectUser.User = user;
                    }
                }
            }
        }

        #endregion

        #region Add & Remove Plan

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Plan AddDailyPlan(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var plan = new Plan
                           {
                               RowId = Guid.NewGuid(),
                               CreatedDate = DateTime.Now,
                           };
            InternalPlans.Add(plan);
            plan.IsDeleted = false;
            plan.ModifiedDate = DateTime.Now;
            plan.ModifiedByUser = modifiedUser;
            plan.BeginDate = DateTime.Now.Date.AddDays(1);
            plan.EndDate = DateTime.Now.Date.AddDays(1);
            plan.PlannedByUser = modifiedUser;
            return plan;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Plan AddWeeklyPlan(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var plan = new Plan
                           {
                               RowId = Guid.NewGuid(),
                               CreatedDate = DateTime.Now,
                           };
            InternalPlans.Add(plan);
            plan.IsDeleted = false;
            plan.ModifiedDate = DateTime.Now;
            plan.ModifiedByUser = modifiedUser;
            plan.BeginDate = DateTime.Now.Date.AddDays(-(int) DateTime.Now.DayOfWeek).AddDays(7);
            plan.EndDate = plan.BeginDate.AddDays(7);
            plan.PlannedByUser = modifiedUser;
            return plan;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Plan AddMonthlyPlan(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var plan = new Plan
                           {
                               RowId = Guid.NewGuid(),
                               CreatedDate = DateTime.Now,
                           };
            InternalPlans.Add(plan);
            plan.IsDeleted = false;
            plan.ModifiedDate = DateTime.Now;
            plan.ModifiedByUser = modifiedUser;
            plan.BeginDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1).AddMonths(1);
            plan.EndDate = plan.BeginDate.AddMonths(1);
            plan.PlannedByUser = modifiedUser;
            return plan;
        }

        /// <summary>
        /// </summary>
        /// <param name = "plan"></param>
        /// <param name = "modifiedUser"></param>
        public void RemovePlan(Plan plan, User modifiedUser)
        {
            if (plan == null)
            {
                throw new ArgumentNullException("plan");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalPlans.Contains(plan))
            {
                plan.Delete(modifiedUser);
            }
        }

        #endregion

        #region Add & Remove Report

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Report AddDailyReport(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var report = new Report
                             {
                                 RowId = Guid.NewGuid(),
                                 CreatedDate = DateTime.Now,
                             };
            InternalReports.Add(report);
            report.IsDeleted = false;
            report.ModifiedDate = DateTime.Now;
            report.ModifiedByUser = modifiedUser;
            report.ReportTypeId = 1;
            report.BeginDate = DateTime.Now.Date;
            report.EndDate = DateTime.Now.Date.AddDays(1);
            report.ReportedByUser = modifiedUser;
            return report;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Report AddWeeklyReport(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var report = new Report
                             {
                                 RowId = Guid.NewGuid(),
                                 CreatedDate = DateTime.Now,
                             };
            InternalReports.Add(report);
            report.IsDeleted = false;
            report.ModifiedDate = DateTime.Now;
            report.ModifiedByUser = modifiedUser;
            report.ReportTypeId = 2;
            report.BeginDate = DateTime.Now.Date.AddDays(-(int) DateTime.Now.DayOfWeek);
            report.EndDate = report.BeginDate.AddDays(7);
            report.ReportedByUser = modifiedUser;
            return report;
        }

        /// <summary>
        /// </summary>
        /// <returns></returns>
        public Report AddMonthlyReport(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            var report = new Report
                             {
                                 RowId = Guid.NewGuid(),
                                 CreatedDate = DateTime.Now,
                             };
            InternalReports.Add(report);
            report.IsDeleted = false;
            report.ModifiedDate = DateTime.Now;
            report.ModifiedByUser = modifiedUser;
            report.ReportTypeId = 3;
            report.BeginDate = new DateTime(DateTime.Now.Year, DateTime.Now.Month, 1);
            report.EndDate = report.BeginDate.AddMonths(1);
            report.ReportedByUser = modifiedUser;
            return report;
        }

        /// <summary>
        /// </summary>
        /// <param name = "report"></param>
        /// <param name = "modifiedUser"></param>
        public void RemoveReport(Report report, User modifiedUser)
        {
            if (report == null)
            {
                throw new ArgumentNullException("report");
            }
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            if (InternalReports.Contains(report))
            {
                report.Delete(modifiedUser);
            }
        }

        #endregion

        #region Ensure

        /// <summary>
        /// </summary>
        public void Ensure()
        {
            if (string.IsNullOrEmpty(Name))
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture, Resources.NotNullAllowed, RowId, "Project", "Name"));
            }
            if (string.IsNullOrEmpty(Code))
            {
                throw new EntityException(string.Format(CultureInfo.CurrentCulture, Resources.NotNullAllowed, RowId, "Project", "Code"));
            }
            Name = Name.Length > 64 ? Name.Substring(0, 64) : Name;
            Code = Code.Length > 32 ? Code.Substring(0, 32) : Code;
            Description = string.IsNullOrEmpty(Description) ? null : Description.Length > 512 ? Description.Substring(0, 512) : Description;
        }

        #endregion

        #region Delete

        /// <summary>
        /// </summary>
        public void Delete(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            IsDeleted = true;
            ModifiedDate = DateTime.Now;
            ModifiedByUser = modifiedUser;
            ((List<Building>) Buildings).ForEach(building => building.Delete(modifiedUser));
            ((List<Employee>) Employees).ForEach(employee => employee.Delete(modifiedUser));
            ((List<Customer>) Customers).ForEach(customer => customer.Delete(modifiedUser));
            ((List<ProjectAlertTypeSetting>) ProjectAlertTypeSettings).ForEach(alertTypeSetting => alertTypeSetting.Delete(modifiedUser));
            ((List<ProjectRoomType>) ProjectRoomTypes).ForEach(projectRoomType => projectRoomType.Delete(modifiedUser));
            ((List<ProjectUser>) ProjectUsers).ForEach(projectUser => projectUser.Delete(modifiedUser));
            ((List<Plan>) Plans).ForEach(plan => plan.Delete(modifiedUser));
            ((List<Report>) Reports).ForEach(report => report.Delete(modifiedUser));
        }

        /// <summary>
        /// </summary>
        public void CancelDelete(User modifiedUser)
        {
            if (modifiedUser == null)
            {
                throw new ArgumentNullException("modifiedUser");
            }
            IsDeleted = false;
            ModifiedDate = DateTime.Now;
            ModifiedByUser = modifiedUser;
        }

        #endregion
    }
}